local desc_role_exmode = [[
  # 身份模式·改
  ---
  
  基于身份模式，房主于开始游戏后为对局增加任意条规则。

  ---

  ## 已有规则

  明察：主公获得技能【明察】，开局时可主动查看一名角色是否为反贼（其他玩家可见）。

  ---
  
  命途技：以下角色于特定时机获得以下对应其势力的技能：

  主公：游戏开始时获得之。

  内奸：当有角色死亡后，可以亮出身份后获得之。

   
    
  猎：锁定技，你使用【杀】的次数上限+1。

  护：每回合限一次，当一名角色于回合内首次造成伤害时，你可以弃置一个区域的所有牌并防止之。。

  丰：每轮结束时，你可以令一名体力值唯一最小或为1的角色回复1点体力。

  毁：限定技，出牌阶段，你可以分配1点火焰伤害。

  忆：出牌阶段限一次，你可以将两张牌当上一张被使用的基本牌或普通锦囊牌使用。
  
  识：准备阶段，你可以卜算2。

  谐：每回合限一次，当你受到伤害后，你可以摸一张牌并分配一张牌。

  虚：出牌阶段限一次，你可以依次弃置你与一名其他角色各一张牌。
  
  其它势力：随机获得一个其他命途技。

  ---
  
  双内：仅6/8人场生效，一名反贼替换为内奸。
]]

Fk:loadTranslationTable{
  ["#role_exmode_rule_log"] = "本局游戏增加规则：%arg。",
  ["#role_exmode_rule_choose"] = "你可以为对局增加任意条规则",
  ["#role_exmode_rule_mingcha"] = "明察",
  [":#role_exmode_rule_mingcha"] = "主公获得【明察】<br>建议6人/8人场开启",
  ["#role_exmode_rule_mingtu"] = "命途技",
  [":#role_exmode_rule_mingtu"] = "主公获得与其势力相关的命途技，内奸于特定时机可亮出身份获得与其势力相关的命途技<br>建议：6人/8人场开启，与“明察”同步开启；单数人数场不做推荐。",
  ["#role_exmode_rule_shuangnei"] = "双内",
  [":#role_exmode_rule_shuangnei"] = "一名反贼替换为内奸", 
  ["lose_renegade"] = "内奸",
}


local role_getlogic = function()
  local role_logic = GameLogic:subclass("role_logic_exmode")
  local rule = {}

  function role_logic:assignRoles()
    
    local room = self.room
    local n = #room.players
    local roles = self.role_table[n]  -- 对局身份
    table.shuffle(roles)

    local function getPlayerByScreenName(room, name)
      return table.find(room.players, function(p)
        return p._splayer:getScreenName() == name
      end)
    end
    local croom = room.room
    local cowner = croom:getOwner()
    
    local owner = getPlayerByScreenName(room, cowner:getScreenName())
    local list = {
      "#role_exmode_rule_mingcha",
      "#role_exmode_rule_mingtu",
    }
    if n == 8 or n == 6 then
      table.insert(list, 1, "#role_exmode_rule_shuangnei")
    end
    rule = room:askToChoices(owner,{
      min_num = 1,
      max_num = #list,
      choices = list,
      skill_name = "game_rule",
      prompt = "#role_exmode_rule_choose",
      cancelable = true,
      detailed = true,
    })
    if table.contains(rule,"#role_exmode_rule_shuangnei") then -- 双内
      for i, role in ipairs(roles) do
        if role == "rebel" then
          roles[i] = "renegade"
          break
        end
      end
    end

    for i = 1, n do
      local p = room.players[i]
      p.role = roles[i]
      if p.role == "lord" then
        room:setPlayerProperty(p, "role_shown", true)
      end
      room:broadcastProperty(p, "role")
      --room:setPlayerProperty(p, "role_shown", true) ------------------test身份全亮
    end
    local function getOtherPlayers(room, p)
      local ret = table.simpleClone(room.players)
      table.removeOne(ret, p)
      return ret
    end

  end

  function role_logic:chooseGenerals()
    local room = self.room ---@class Room
    local generalNum = room:getSettings('generalNum')
    local n = room:getSettings('enableDeputy') and 2 or 1
    local lord = room:getLord()
    local lord_generals = {}
    local lord_num = 3

    if lord ~= nil then
      room:setCurrent(lord)
      local a1 = #room.general_pile
      local a2 = #room.players * generalNum
      if a1 < a2 then
        room:sendLog{
          type = "#NoEnoughGeneralDraw",
          arg = a1,
          arg2 = a2,
          toast = true,
        }
        room:gameOver("")
      end
      lord_num = math.min(a1 - a2, lord_num)
      local generals = table.connect(room:findGenerals(function(g)
        return table.contains(Fk.lords, g)
      end, lord_num), room:getNGenerals(generalNum))
      lord_generals = room:askToChooseGeneral(lord, { generals = generals, n = n })
      local lord_general, deputy
      if type(lord_generals) == "table" then
        deputy = lord_generals[2]
        lord_general = lord_generals[1]
      else
        lord_general = lord_generals
        lord_generals = {lord_general}
      end
      generals = table.filter(generals, function(g)
        return not table.find(lord_generals, function(lg)
          return Fk.generals[lg].trueName == Fk.generals[g].trueName
        end)
      end)
      room:returnToGeneralPile(generals)

      room:prepareGeneral(lord, lord_general, deputy, true)

      room:askToChooseKingdom({lord})
      room:broadcastProperty(lord, "kingdom")

      -- 显示技能
      local canAttachSkill = function(player, skillName)
        local skill = Fk.skills[skillName]
        if not skill then
          fk.qCritical("Skill: "..skillName.." doesn't exist!")
          return false
        end
        if skill:hasTag(Skill.Lord) and not (player.role == "lord" and player.role_shown and room:isGameMode("role_mode")) then
          return false
        end

        if skill:hasTag(Skill.AttachedKingdom) and not table.contains(skill:getSkeleton().attached_kingdom, player.kingdom) then
          return false
        end

        return true
      end

      local lord_skills = {}
      for _, s in ipairs(Fk.generals[lord.general].skills) do
        if canAttachSkill(lord, s.name) then
          table.insertIfNeed(lord_skills, s.name)
        end
      end
      for _, sname in ipairs(Fk.generals[lord.general].other_skills) do
        if canAttachSkill(lord, sname) then
          table.insertIfNeed(lord_skills, sname)
        end
      end

      local deputyGeneral = Fk.generals[lord.deputyGeneral]
      if deputyGeneral then
        for _, s in ipairs(deputyGeneral.skills) do
          if canAttachSkill(lord, s.name) then
            table.insertIfNeed(lord_skills, s.name)
          end
        end
        for _, sname in ipairs(deputyGeneral.other_skills) do
          if canAttachSkill(lord, sname) then
            table.insertIfNeed(lord_skills, sname)
          end
        end
      end
      for _, skill in ipairs(lord_skills) do
        room:doBroadcastNotify("AddSkill", {
          lord.id,
          skill
        })
      end
    end
    local nonlord = room:getOtherPlayers(lord, true)
    local req = Request:new(nonlord, "AskForGeneral")
    local generals = table.random(room.general_pile, #nonlord * generalNum)
    for i, p in ipairs(nonlord) do
      local arg = table.slice(generals, (i - 1) * generalNum + 1, i * generalNum + 1)
      req:setData(p, { arg, n })
      req:setDefaultReply(p, table.random(arg, n))
    end

    for _, p in ipairs(nonlord) do
      local result = req:getResult(p)
      local general, deputy = result[1], result[2]
      room:findGeneral(general)
      room:findGeneral(deputy)
      room:prepareGeneral(p, general, deputy)
    end

    room:askToChooseKingdom(nonlord)
  end

  function role_logic:attachSkillToPlayers()
    local room = self.room
    local lord = room:getLord()

    local addRoleModSkills = function(player, skillName)
      local skill = Fk.skills[skillName]
      if not skill then
        fk.qCritical("Skill: "..skillName.." doesn't exist!")
        return
      end
      if skill:hasTag(Skill.Lord) and not (player.role == "lord" and player.role_shown and room:isGameMode("role_mode")) then
        return
      end

      if skill:hasTag(Skill.AttachedKingdom) and not table.contains(skill:getSkeleton().attached_kingdom, player.kingdom) then
        return
      end

      room:handleAddLoseSkills(player, skillName, nil, false, true)
      self:trigger(fk.EventAcquireSkill, player, {skill = skill, who = player})
    end
    for _, p in ipairs(room.alive_players) do
      local skills = Fk.generals[p.general]:getSkillNameList(true)
      for _, s in ipairs(skills) do
        addRoleModSkills(p, s)
      end

      local deputy = Fk.generals[p.deputyGeneral]
      if deputy then
        skills = deputy:getSkillNameList(true)
        for _, s in ipairs(skills) do
          addRoleModSkills(p, s)
        end
      end
    end
    if table.contains(rule,"#role_exmode_rule_mingcha") then
      room:handleAddLoseSkills(lord, "role_exmode_mingcha", nil, false, true)
    end
    if table.contains(rule,"#role_exmode_rule_mingtu") then
      ----------test
      --[[
      local renegade = table.find(room.alive_players, function (to)
        return to.role == "renegade"
      end)
      if renegade then
        renegade.role_shown = true
        room:broadcastProperty(renegade, "role_shown")
        --room:handleAddLoseSkills(renegade, "#role_exmode_rule_mingtu&", nil, false, true)
        renegade:addFakeSkill("#role_exmode_rule_mingtu&")
      end
      --]]
      for _, p in ipairs(room.players) do
        p:addFakeSkill("#role_exmode_rule_mingtu&")
      end
      -------------test
      room:addSkill("#role_exmode_rule_mingtu&")
      local kingdom = lord.kingdom
      local list = { "lb_hui", "lb_lie", "lb_shi", "lb_xie", "lb_xu", "lb_feng", "lb_hu", "lb_yi", }
      if not table.contains(list, lord.kingdom) then
        kingdom = table.random(list)
      end
      if Fk.skills["role_exmode_mingtu__"..kingdom] then
        room:handleAddLoseSkills(lord, "role_exmode_mingtu__"..kingdom, nil, false, true)
      end
    end
    if #rule > 0 then
      room:sendLog{
        type = "#role_exmode_rule_log",
        arg = table.concat(table.map(rule, function(name)
          return "〖" .. Fk:translate(name) .. "〗"
        end), "/"),
        toast = true,
      }
    end
  end


  return role_logic
end

local role_mode = fk.CreateGameMode{
  name = "role_exmode", -- just to let it at the top of list
  minPlayer = 2,
  maxPlayer = 8,
  logic = role_getlogic,
  main_mode = "role_mode",
  is_counted = function(self, room)
    return #room.players >= 5
  end,
  --rule = "#role_exmode_rule&",
  winner_getter = function (self, victim)
    if not victim.surrendered and victim.rest > 0 then
      return ""
    end

    local room = victim.room
    local winner = ""
    local alive = table.filter(room.players, function(p)
      return not p.surrendered and not (p.dead and p.rest == 0) and p.role ~= "civilian"
    end)

    if victim.role == "lord" then
      if #alive == 1 and alive[1].role == "renegade" then
        for _, to in ipairs(room.players) do
          if to.role == "renegade" and to ~= alive[1] then
            to.role = "lose_renegade" -- 不影响胜率的身份
            room:broadcastProperty(to, "role")
          end
        end
        winner = "renegade"
      else
        winner = "rebel+rebel_chief"
      end
    elseif victim.role ~= "loyalist" then
      local lord_win = true
      for _, p in ipairs(alive) do
        if p.role == "rebel" or p.role == "rebel_chief" or p.role == "renegade" then
          lord_win = false
          break
        end
      end
      if lord_win then
        winner = "lord+loyalist"
      end
    end

    if winner ~= "" then
      winner = winner.. "+civilian"
    end

    return winner
  end,
  surrender_func = function(self, playedTime)
    local roleCheck = false
    local roleText = ""

    local alive_players = table.filter(Fk:currentRoom().players, function(p)
      return not p.dead or p.rest > 0
    end)

    if Self.role == "renegade" then
      roleCheck = not table.find(alive_players, function(p)
        return p ~= Self and table.contains({"rebel", "rebel_chief", "renegade"}, p.role)
      end)
      roleText = "left lord and loyalist alive"
    elseif Self.role == "rebel" or Self.role == "rebel_chief" then
      roleCheck = #table.filter(alive_players, function(p)
        return table.contains({"rebel", "rebel_chief", "renegade"}, p.role)
      end) == 1
      roleText = "left one rebel alive"
    else
      if Self.role == "loyalist" or Self.role == "civilian" then
        return { { text = Self.role.." never surrender", passed = false } }
      else
        if #alive_players < 3 then
          roleCheck = true
        else
          roleText = "left you alive"
          local left_loyalist, left_rebel, left_renegade = false, false, false
          for _, p in ipairs(alive_players) do
            if p ~= Self then
              if table.contains({"lord", "loyalist"}, p.role) then
                left_loyalist = true
                break
              else
                if table.contains({"rebel", "rebel_chief"}, p.role) then
                  left_rebel = true
                elseif p.role == "renegade" then
                  left_renegade = true
                end
              end
            end
          end
          if left_loyalist then
            roleCheck = false
          else
            roleCheck = not (left_rebel and left_renegade)
          end
        end
      end
    end

    return {
      { text = "time limitation: 5 min", passed = playedTime >= 300 },
      { text = roleText, passed = roleCheck },
    }
  end,
}

Fk:loadTranslationTable{
  ["time limitation: 5 min"] = "游戏时长达到5分钟",
  ["left lord and loyalist alive"] = "仅剩你和主忠方存活",
  ["left one rebel alive"] = "反贼仅剩你存活且不存在存活内奸",
  ["left you alive"] = "主忠方仅剩你存活且其他阵营仅剩一方",
  ["loyalist never surrender"] = "忠臣永不投降！",
  ["civilian never surrender"] = "平民坚持就是成功！",
}

Fk:loadTranslationTable{
  ["role_exmode"] = "身份模式·改",
  [":role_exmode"] = desc_role_exmode,
}

return role_mode
